//===----------------------------------------------------------------------===//
//
// This source file is part of the Soto for AWS open source project
//
// Copyright (c) 2017-2024 the Soto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Soto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

// THIS FILE IS AUTOMATICALLY GENERATED by https://github.com/soto-project/soto-codegenerator.
// DO NOT EDIT.

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
@_spi(SotoInternal) import SotoCore

extension KeyspacesStreams {
    // MARK: Enums

    public enum OriginType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case replication = "REPLICATION"
        case ttl = "TTL"
        case user = "USER"
        public var description: String { return self.rawValue }
    }

    public enum ShardFilterType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case childShards = "CHILD_SHARDS"
        public var description: String { return self.rawValue }
    }

    public enum ShardIteratorType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case afterSequenceNumber = "AFTER_SEQUENCE_NUMBER"
        case atSequenceNumber = "AT_SEQUENCE_NUMBER"
        case latest = "LATEST"
        case trimHorizon = "TRIM_HORIZON"
        public var description: String { return self.rawValue }
    }

    public enum StreamStatus: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case disabled = "DISABLED"
        case disabling = "DISABLING"
        case enabled = "ENABLED"
        case enabling = "ENABLING"
        public var description: String { return self.rawValue }
    }

    public enum StreamViewType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case keysOnly = "KEYS_ONLY"
        case newAndOldImages = "NEW_AND_OLD_IMAGES"
        case newImage = "NEW_IMAGE"
        case oldImage = "OLD_IMAGE"
        public var description: String { return self.rawValue }
    }

    public enum ValidationExceptionType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case expiredIterator = "ExpiredIterator"
        case expiredNextToken = "ExpiredNextToken"
        case invalidFormat = "InvalidFormat"
        case trimmedDataAccess = "TrimmedDataAccess"
        public var description: String { return self.rawValue }
    }

    public enum KeyspacesCellValue: AWSDecodableShape, Sendable {
        /// A value of ASCII text type, containing US-ASCII characters.
        case asciiT(String)
        /// A 64-bit signed integer value.
        case bigintT(String)
        /// A binary large object (BLOB) value stored as a Base64-encoded string.
        case blobT(AWSBase64Data)
        /// A Boolean value, either true or false.
        case boolT(Bool)
        /// A distributed counter value that can be incremented and decremented.
        case counterT(String)
        /// A date value without a time component, represented as days since epoch (January 1, 1970).
        case dateT(String)
        /// A variable-precision decimal number value.
        case decimalT(String)
        /// A 64-bit double-precision floating point value.
        case doubleT(String)
        /// A 32-bit single-precision floating point value.
        case floatT(String)
        /// An IP address value, either IPv4 or IPv6 format.
        case inetT(String)
        /// A 32-bit signed integer value.
        case intT(String)
        /// An ordered collection of elements that can contain duplicate values.
        case listT([KeyspacesCell])
        /// A collection of key-value pairs where each key is unique.
        case mapT([KeyspacesCellMapDefinition])
        /// An unordered collection of unique elements.
        case setT([KeyspacesCell])
        /// A 16-bit signed integer value.
        case smallintT(String)
        /// A UTF-8 encoded string value.
        case textT(String)
        /// A timestamp value representing date and time with millisecond precision.
        case timestampT(String)
        /// A time value without a date component, with nanosecond precision.
        case timeT(String)
        /// A universally unique identifier (UUID) that includes a timestamp component, ensuring both uniqueness and time ordering.
        case timeuuidT(String)
        /// An 8-bit signed integer value.
        case tinyintT(String)
        /// A fixed-length ordered list of elements, where each element can be of a different data type.
        case tupleT([KeyspacesCell])
        /// A user-defined type (UDT) value consisting of named fields, each with its own data type.
        case udtT([String: KeyspacesCell])
        /// A universally unique identifier (UUID) value.
        case uuidT(String)
        /// A UTF-8 encoded string value, functionally equivalent to text type.
        case varcharT(String)
        /// A variable precision integer value with arbitrary length.
        case varintT(String)

        public init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            guard container.allKeys.count == 1, let key = container.allKeys.first else {
                let context = DecodingError.Context(
                    codingPath: container.codingPath,
                    debugDescription: "Expected exactly one key, but got \(container.allKeys.count)"
                )
                throw DecodingError.dataCorrupted(context)
            }
            switch key {
            case .asciiT:
                let value = try container.decode(String.self, forKey: .asciiT)
                self = .asciiT(value)
            case .bigintT:
                let value = try container.decode(String.self, forKey: .bigintT)
                self = .bigintT(value)
            case .blobT:
                let value = try container.decode(AWSBase64Data.self, forKey: .blobT)
                self = .blobT(value)
            case .boolT:
                let value = try container.decode(Bool.self, forKey: .boolT)
                self = .boolT(value)
            case .counterT:
                let value = try container.decode(String.self, forKey: .counterT)
                self = .counterT(value)
            case .dateT:
                let value = try container.decode(String.self, forKey: .dateT)
                self = .dateT(value)
            case .decimalT:
                let value = try container.decode(String.self, forKey: .decimalT)
                self = .decimalT(value)
            case .doubleT:
                let value = try container.decode(String.self, forKey: .doubleT)
                self = .doubleT(value)
            case .floatT:
                let value = try container.decode(String.self, forKey: .floatT)
                self = .floatT(value)
            case .inetT:
                let value = try container.decode(String.self, forKey: .inetT)
                self = .inetT(value)
            case .intT:
                let value = try container.decode(String.self, forKey: .intT)
                self = .intT(value)
            case .listT:
                let value = try container.decode([KeyspacesCell].self, forKey: .listT)
                self = .listT(value)
            case .mapT:
                let value = try container.decode([KeyspacesCellMapDefinition].self, forKey: .mapT)
                self = .mapT(value)
            case .setT:
                let value = try container.decode([KeyspacesCell].self, forKey: .setT)
                self = .setT(value)
            case .smallintT:
                let value = try container.decode(String.self, forKey: .smallintT)
                self = .smallintT(value)
            case .textT:
                let value = try container.decode(String.self, forKey: .textT)
                self = .textT(value)
            case .timestampT:
                let value = try container.decode(String.self, forKey: .timestampT)
                self = .timestampT(value)
            case .timeT:
                let value = try container.decode(String.self, forKey: .timeT)
                self = .timeT(value)
            case .timeuuidT:
                let value = try container.decode(String.self, forKey: .timeuuidT)
                self = .timeuuidT(value)
            case .tinyintT:
                let value = try container.decode(String.self, forKey: .tinyintT)
                self = .tinyintT(value)
            case .tupleT:
                let value = try container.decode([KeyspacesCell].self, forKey: .tupleT)
                self = .tupleT(value)
            case .udtT:
                let value = try container.decode([String: KeyspacesCell].self, forKey: .udtT)
                self = .udtT(value)
            case .uuidT:
                let value = try container.decode(String.self, forKey: .uuidT)
                self = .uuidT(value)
            case .varcharT:
                let value = try container.decode(String.self, forKey: .varcharT)
                self = .varcharT(value)
            case .varintT:
                let value = try container.decode(String.self, forKey: .varintT)
                self = .varintT(value)
            }
        }

        private enum CodingKeys: String, CodingKey {
            case asciiT = "asciiT"
            case bigintT = "bigintT"
            case blobT = "blobT"
            case boolT = "boolT"
            case counterT = "counterT"
            case dateT = "dateT"
            case decimalT = "decimalT"
            case doubleT = "doubleT"
            case floatT = "floatT"
            case inetT = "inetT"
            case intT = "intT"
            case listT = "listT"
            case mapT = "mapT"
            case setT = "setT"
            case smallintT = "smallintT"
            case textT = "textT"
            case timestampT = "timestampT"
            case timeT = "timeT"
            case timeuuidT = "timeuuidT"
            case tinyintT = "tinyintT"
            case tupleT = "tupleT"
            case udtT = "udtT"
            case uuidT = "uuidT"
            case varcharT = "varcharT"
            case varintT = "varintT"
        }
    }

    // MARK: Shapes

    public struct GetRecordsInput: AWSEncodableShape {
        ///  The maximum number of records to return in a single GetRecords request. Default value is 1000. You can specify a limit between 1 and 1000, but the actual number returned might be less than the specified maximum if the size of the data for the returned records exceeds the internal size limit.
        public let maxResults: Int?
        ///  The unique identifier of the shard iterator. A shard iterator specifies the position in the shard from which you want to start reading data records sequentially. You obtain this value by calling the GetShardIterator operation. Each shard iterator is valid for 15 minutes after creation.
        public let shardIterator: String

        @inlinable
        public init(maxResults: Int? = nil, shardIterator: String) {
            self.maxResults = maxResults
            self.shardIterator = shardIterator
        }

        public func validate(name: String) throws {
            try self.validate(self.shardIterator, name: "shardIterator", parent: name, max: 4096)
            try self.validate(self.shardIterator, name: "shardIterator", parent: name, min: 1)
        }

        private enum CodingKeys: String, CodingKey {
            case maxResults = "maxResults"
            case shardIterator = "shardIterator"
        }
    }

    public struct GetRecordsOutput: AWSDecodableShape {
        ///  An array of change data records retrieved from the specified shard. Each record represents a single data modification (insert, update, or delete) to a row in the Amazon Keyspaces table. Records include the primary key columns and information about what data was modified.
        public let changeRecords: [Record]?
        ///  The next position in the shard from which to start sequentially reading data records. If null, the shard has been closed and the requested iterator doesn't return any more data.
        public let nextShardIterator: String?

        @inlinable
        public init(changeRecords: [Record]? = nil, nextShardIterator: String? = nil) {
            self.changeRecords = changeRecords
            self.nextShardIterator = nextShardIterator
        }

        private enum CodingKeys: String, CodingKey {
            case changeRecords = "changeRecords"
            case nextShardIterator = "nextShardIterator"
        }
    }

    public struct GetShardIteratorInput: AWSEncodableShape {
        ///  The sequence number of the data record in the shard from which to start reading. Required if ShardIteratorType is AT_SEQUENCE_NUMBER or AFTER_SEQUENCE_NUMBER. This parameter is ignored for other iterator types.
        public let sequenceNumber: String?
        ///  The identifier of the shard within the stream. The shard ID uniquely identifies a subset of the stream's data records that you want to access.
        public let shardId: String
        ///  Determines how the shard iterator is positioned. Must be one of the following:    TRIM_HORIZON - Start reading at the last untrimmed record in the shard, which is the oldest data record in the shard.    AT_SEQUENCE_NUMBER - Start reading exactly from the specified sequence number.    AFTER_SEQUENCE_NUMBER - Start reading right after the specified sequence number.    LATEST - Start reading just after the most recent record in the shard, so that you always read the most recent data.
        public let shardIteratorType: ShardIteratorType
        ///  The Amazon Resource Name (ARN) of the stream for which to get the shard iterator. The ARN uniquely identifies the stream within Amazon Keyspaces.
        public let streamArn: String

        @inlinable
        public init(sequenceNumber: String? = nil, shardId: String, shardIteratorType: ShardIteratorType, streamArn: String) {
            self.sequenceNumber = sequenceNumber
            self.shardId = shardId
            self.shardIteratorType = shardIteratorType
            self.streamArn = streamArn
        }

        public func validate(name: String) throws {
            try self.validate(self.sequenceNumber, name: "sequenceNumber", parent: name, max: 48)
            try self.validate(self.sequenceNumber, name: "sequenceNumber", parent: name, min: 21)
            try self.validate(self.shardId, name: "shardId", parent: name, max: 65)
            try self.validate(self.shardId, name: "shardId", parent: name, min: 28)
            try self.validate(self.streamArn, name: "streamArn", parent: name, max: 1024)
            try self.validate(self.streamArn, name: "streamArn", parent: name, min: 37)
        }

        private enum CodingKeys: String, CodingKey {
            case sequenceNumber = "sequenceNumber"
            case shardId = "shardId"
            case shardIteratorType = "shardIteratorType"
            case streamArn = "streamArn"
        }
    }

    public struct GetShardIteratorOutput: AWSDecodableShape {
        ///  The unique identifier for the shard iterator. This value is used in the GetRecords operation to retrieve data records from the specified shard. Each shard iterator expires 15 minutes after it is returned to the requester.
        public let shardIterator: String?

        @inlinable
        public init(shardIterator: String? = nil) {
            self.shardIterator = shardIterator
        }

        private enum CodingKeys: String, CodingKey {
            case shardIterator = "shardIterator"
        }
    }

    public struct GetStreamInput: AWSEncodableShape {
        ///  The maximum number of shard objects to return in a single GetStream request. Default value is 100. The minimum value is 1 and the maximum value is 100.
        public let maxResults: Int?
        ///  An optional pagination token provided by a previous GetStream operation. If this parameter is specified, the response includes only records beyond the token, up to the value specified by maxResults.
        public let nextToken: String?
        ///  Optional filter criteria to apply when retrieving shards. You can filter shards based on their state or other attributes to narrow down the results returned by the GetStream operation.
        public let shardFilter: ShardFilter?
        ///  The Amazon Resource Name (ARN) of the stream for which detailed information is requested. This uniquely identifies the specific stream you want to get information about.
        public let streamArn: String

        @inlinable
        public init(maxResults: Int? = nil, nextToken: String? = nil, shardFilter: ShardFilter? = nil, streamArn: String) {
            self.maxResults = maxResults
            self.nextToken = nextToken
            self.shardFilter = shardFilter
            self.streamArn = streamArn
        }

        public func validate(name: String) throws {
            try self.validate(self.nextToken, name: "nextToken", parent: name, max: 3000)
            try self.validate(self.nextToken, name: "nextToken", parent: name, min: 80)
            try self.shardFilter?.validate(name: "\(name).shardFilter")
            try self.validate(self.streamArn, name: "streamArn", parent: name, max: 1024)
            try self.validate(self.streamArn, name: "streamArn", parent: name, min: 37)
        }

        private enum CodingKeys: String, CodingKey {
            case maxResults = "maxResults"
            case nextToken = "nextToken"
            case shardFilter = "shardFilter"
            case streamArn = "streamArn"
        }
    }

    public struct GetStreamOutput: AWSDecodableShape {
        ///  The date and time when the request to create this stream was issued. The value is represented in ISO 8601 format.
        public let creationRequestDateTime: Date
        ///  The name of the keyspace containing the table associated with this stream. The keyspace name is part of the table's hierarchical identifier in Amazon Keyspaces.
        public let keyspaceName: String
        ///  A pagination token that can be used in a subsequent GetStream request. This token is returned if the response contains more shards than can be returned in a single response.
        public let nextToken: String?
        ///  An array of shard objects associated with this stream. Each shard contains a subset of the stream's data records and has its own unique identifier. The collection of shards represents the complete stream data.
        public let shards: [Shard]?
        ///  The Amazon Resource Name (ARN) that uniquely identifies the stream within Amazon Keyspaces. This ARN can be used in other API operations to reference this specific stream.
        public let streamArn: String
        ///  A timestamp that serves as a unique identifier for this stream, used for debugging and monitoring purposes. The stream label represents the point in time when the stream was created.
        public let streamLabel: String
        ///  The current status of the stream. Values can be ENABLING, ENABLED, DISABLING, or DISABLED. Operations on the stream depend on its current status.
        public let streamStatus: StreamStatus
        ///  The format of the data records in this stream. Currently, this can be one of the following options:    NEW_AND_OLD_IMAGES - both versions of the row, before and after the change. This is the default.    NEW_IMAGE - the version of the row after the change.    OLD_IMAGE - the version of the row before the change.    KEYS_ONLY - the partition and clustering keys of the row that was changed.
        public let streamViewType: StreamViewType
        ///  The name of the table associated with this stream. The stream captures changes to rows in this Amazon Keyspaces table.
        public let tableName: String

        @inlinable
        public init(creationRequestDateTime: Date, keyspaceName: String, nextToken: String? = nil, shards: [Shard]? = nil, streamArn: String, streamLabel: String, streamStatus: StreamStatus, streamViewType: StreamViewType, tableName: String) {
            self.creationRequestDateTime = creationRequestDateTime
            self.keyspaceName = keyspaceName
            self.nextToken = nextToken
            self.shards = shards
            self.streamArn = streamArn
            self.streamLabel = streamLabel
            self.streamStatus = streamStatus
            self.streamViewType = streamViewType
            self.tableName = tableName
        }

        private enum CodingKeys: String, CodingKey {
            case creationRequestDateTime = "creationRequestDateTime"
            case keyspaceName = "keyspaceName"
            case nextToken = "nextToken"
            case shards = "shards"
            case streamArn = "streamArn"
            case streamLabel = "streamLabel"
            case streamStatus = "streamStatus"
            case streamViewType = "streamViewType"
            case tableName = "tableName"
        }
    }

    public struct KeyspacesCell: AWSDecodableShape {
        /// Metadata associated with this cell, such as time-to-live (TTL) expiration time and write timestamp.
        public let metadata: KeyspacesMetadata?
        /// The value stored in this cell, which can be of various data types supported by Amazon Keyspaces.
        public let value: KeyspacesCellValue?

        @inlinable
        public init(metadata: KeyspacesMetadata? = nil, value: KeyspacesCellValue? = nil) {
            self.metadata = metadata
            self.value = value
        }

        private enum CodingKeys: String, CodingKey {
            case metadata = "metadata"
            case value = "value"
        }
    }

    public struct KeyspacesCellMapDefinition: AWSDecodableShape {
        /// The key of this map entry in the Amazon Keyspaces cell.
        public let key: KeyspacesCellValue?
        /// Metadata for this specific key-value pair within the map, such as timestamps and TTL information.
        public let metadata: KeyspacesMetadata?
        /// The value associated with the key in this map entry.
        public let value: KeyspacesCellValue?

        @inlinable
        public init(key: KeyspacesCellValue? = nil, metadata: KeyspacesMetadata? = nil, value: KeyspacesCellValue? = nil) {
            self.key = key
            self.metadata = metadata
            self.value = value
        }

        private enum CodingKeys: String, CodingKey {
            case key = "key"
            case metadata = "metadata"
            case value = "value"
        }
    }

    public struct KeyspacesMetadata: AWSDecodableShape {
        /// The time at which the associated data will expire, based on the time-to-live (TTL) setting.
        public let expirationTime: String?
        /// The timestamp at which the associated data was written to the database.
        public let writeTime: String?

        @inlinable
        public init(expirationTime: String? = nil, writeTime: String? = nil) {
            self.expirationTime = expirationTime
            self.writeTime = writeTime
        }

        private enum CodingKeys: String, CodingKey {
            case expirationTime = "expirationTime"
            case writeTime = "writeTime"
        }
    }

    public struct KeyspacesRow: AWSDecodableShape {
        /// Metadata that applies to the entire row, such as timestamps and TTL information.
        public let rowMetadata: KeyspacesMetadata?
        /// A map of static column cells shared by all rows with the same partition key, where keys are column names and values are the corresponding cells.
        public let staticCells: [String: KeyspacesCell]?
        /// A map of regular (non-static) column cells in the row, where keys are column names and values are the corresponding cells.
        public let valueCells: [String: KeyspacesCell]?

        @inlinable
        public init(rowMetadata: KeyspacesMetadata? = nil, staticCells: [String: KeyspacesCell]? = nil, valueCells: [String: KeyspacesCell]? = nil) {
            self.rowMetadata = rowMetadata
            self.staticCells = staticCells
            self.valueCells = valueCells
        }

        private enum CodingKeys: String, CodingKey {
            case rowMetadata = "rowMetadata"
            case staticCells = "staticCells"
            case valueCells = "valueCells"
        }
    }

    public struct ListStreamsInput: AWSEncodableShape {
        ///  The name of the keyspace for which to list streams. If specified, only streams associated with tables in this keyspace are returned. If omitted, streams from all keyspaces are included in the results.
        public let keyspaceName: String?
        ///  The maximum number of streams to return in a single ListStreams request. Default value is 100. The minimum value is 1 and the maximum value is 100.
        public let maxResults: Int?
        ///  An optional pagination token provided by a previous ListStreams operation. If this parameter is specified, the response includes only records beyond the token, up to the value specified by maxResults.
        public let nextToken: String?
        ///  The name of the table for which to list streams. Must be used together with keyspaceName. If specified, only streams associated with this specific table are returned.
        public let tableName: String?

        @inlinable
        public init(keyspaceName: String? = nil, maxResults: Int? = nil, nextToken: String? = nil, tableName: String? = nil) {
            self.keyspaceName = keyspaceName
            self.maxResults = maxResults
            self.nextToken = nextToken
            self.tableName = tableName
        }

        public func validate(name: String) throws {
            try self.validate(self.keyspaceName, name: "keyspaceName", parent: name, max: 48)
            try self.validate(self.keyspaceName, name: "keyspaceName", parent: name, min: 1)
            try self.validate(self.keyspaceName, name: "keyspaceName", parent: name, pattern: "^[a-zA-Z0-9][a-zA-Z0-9_]{0,47}$")
            try self.validate(self.nextToken, name: "nextToken", parent: name, max: 3000)
            try self.validate(self.nextToken, name: "nextToken", parent: name, min: 80)
            try self.validate(self.tableName, name: "tableName", parent: name, max: 48)
            try self.validate(self.tableName, name: "tableName", parent: name, min: 1)
            try self.validate(self.tableName, name: "tableName", parent: name, pattern: "^[a-zA-Z0-9][a-zA-Z0-9_]{0,47}$")
        }

        private enum CodingKeys: String, CodingKey {
            case keyspaceName = "keyspaceName"
            case maxResults = "maxResults"
            case nextToken = "nextToken"
            case tableName = "tableName"
        }
    }

    public struct ListStreamsOutput: AWSDecodableShape {
        ///  A pagination token that can be used in a subsequent ListStreams request. This token is returned if the response contains more streams than can be returned in a single response based on the MaxResults parameter.
        public let nextToken: String?
        ///  An array of stream objects, each containing summary information about a stream including its ARN, status, and associated table information. This list includes all streams that match the request criteria.
        public let streams: [Stream]?

        @inlinable
        public init(nextToken: String? = nil, streams: [Stream]? = nil) {
            self.nextToken = nextToken
            self.streams = streams
        }

        private enum CodingKeys: String, CodingKey {
            case nextToken = "nextToken"
            case streams = "streams"
        }
    }

    public struct Record: AWSDecodableShape {
        /// The clustering key columns and their values for the affected row, which determine the order of rows within a partition.
        public let clusteringKeys: [String: KeyspacesCellValue]?
        /// The timestamp indicating when this change data capture record was created.
        public let createdAt: Date?
        /// The version of the record format, used to track the evolution of the record structure over time.
        public let eventVersion: String?
        /// The state of the row after the change operation that generated this record.
        public let newImage: KeyspacesRow?
        /// The state of the row before the change operation that generated this record.
        public let oldImage: KeyspacesRow?
        /// The origin or source of this change data capture record.
        public let origin: OriginType?
        /// The partition key columns and their values for the affected row.
        public let partitionKeys: [String: KeyspacesCellValue]?
        /// A unique identifier assigned to this record within the shard, used for ordering and tracking purposes.
        public let sequenceNumber: String?

        @inlinable
        public init(clusteringKeys: [String: KeyspacesCellValue]? = nil, createdAt: Date? = nil, eventVersion: String? = nil, newImage: KeyspacesRow? = nil, oldImage: KeyspacesRow? = nil, origin: OriginType? = nil, partitionKeys: [String: KeyspacesCellValue]? = nil, sequenceNumber: String? = nil) {
            self.clusteringKeys = clusteringKeys
            self.createdAt = createdAt
            self.eventVersion = eventVersion
            self.newImage = newImage
            self.oldImage = oldImage
            self.origin = origin
            self.partitionKeys = partitionKeys
            self.sequenceNumber = sequenceNumber
        }

        private enum CodingKeys: String, CodingKey {
            case clusteringKeys = "clusteringKeys"
            case createdAt = "createdAt"
            case eventVersion = "eventVersion"
            case newImage = "newImage"
            case oldImage = "oldImage"
            case origin = "origin"
            case partitionKeys = "partitionKeys"
            case sequenceNumber = "sequenceNumber"
        }
    }

    public struct SequenceNumberRange: AWSDecodableShape {
        /// The ending sequence number of the range, which may be null for open-ended ranges.
        public let endingSequenceNumber: String?
        /// The starting sequence number of the range.
        public let startingSequenceNumber: String?

        @inlinable
        public init(endingSequenceNumber: String? = nil, startingSequenceNumber: String? = nil) {
            self.endingSequenceNumber = endingSequenceNumber
            self.startingSequenceNumber = startingSequenceNumber
        }

        private enum CodingKeys: String, CodingKey {
            case endingSequenceNumber = "endingSequenceNumber"
            case startingSequenceNumber = "startingSequenceNumber"
        }
    }

    public struct Shard: AWSDecodableShape {
        /// The identifiers of parent shards that this shard evolved from, if this shard was created through resharding.
        public let parentShardIds: [String]?
        /// The range of sequence numbers contained within this shard.
        public let sequenceNumberRange: SequenceNumberRange?
        /// A unique identifier for this shard within the stream.
        public let shardId: String?

        @inlinable
        public init(parentShardIds: [String]? = nil, sequenceNumberRange: SequenceNumberRange? = nil, shardId: String? = nil) {
            self.parentShardIds = parentShardIds
            self.sequenceNumberRange = sequenceNumberRange
            self.shardId = shardId
        }

        private enum CodingKeys: String, CodingKey {
            case parentShardIds = "parentShardIds"
            case sequenceNumberRange = "sequenceNumberRange"
            case shardId = "shardId"
        }
    }

    public struct ShardFilter: AWSEncodableShape {
        /// The identifier of a specific shard used to filter results based on the specified filter type.
        public let shardId: String?
        /// The type of shard filter to use, which determines how the shardId parameter is interpreted.
        public let type: ShardFilterType?

        @inlinable
        public init(shardId: String? = nil, type: ShardFilterType? = nil) {
            self.shardId = shardId
            self.type = type
        }

        public func validate(name: String) throws {
            try self.validate(self.shardId, name: "shardId", parent: name, max: 65)
            try self.validate(self.shardId, name: "shardId", parent: name, min: 28)
        }

        private enum CodingKeys: String, CodingKey {
            case shardId = "shardId"
            case type = "type"
        }
    }

    public struct Stream: AWSDecodableShape {
        /// The name of the keyspace containing the table associated with this stream.
        public let keyspaceName: String
        /// The Amazon Resource Name (ARN) that uniquely identifies this stream.
        public let streamArn: String
        /// A unique identifier for this stream that can be used in stream operations.
        public let streamLabel: String
        /// The name of the table associated with this stream.
        public let tableName: String

        @inlinable
        public init(keyspaceName: String, streamArn: String, streamLabel: String, tableName: String) {
            self.keyspaceName = keyspaceName
            self.streamArn = streamArn
            self.streamLabel = streamLabel
            self.tableName = tableName
        }

        private enum CodingKeys: String, CodingKey {
            case keyspaceName = "keyspaceName"
            case streamArn = "streamArn"
            case streamLabel = "streamLabel"
            case tableName = "tableName"
        }
    }

    public struct ValidationException: AWSErrorShape {
        /// An error occurred validating your request. See the error message for details.
        public let errorCode: ValidationExceptionType?
        /// The input fails to satisfy the constraints specified by the service. Check the error details and modify your request.
        public let message: String?

        @inlinable
        public init(errorCode: ValidationExceptionType? = nil, message: String? = nil) {
            self.errorCode = errorCode
            self.message = message
        }

        private enum CodingKeys: String, CodingKey {
            case errorCode = "errorCode"
            case message = "message"
        }
    }
}

// MARK: - Errors

/// Error enum for KeyspacesStreams
public struct KeyspacesStreamsErrorType: AWSErrorType {
    enum Code: String {
        case accessDeniedException = "AccessDeniedException"
        case internalServerException = "InternalServerException"
        case resourceNotFoundException = "ResourceNotFoundException"
        case throttlingException = "ThrottlingException"
        case validationException = "ValidationException"
    }

    private let error: Code
    public let context: AWSErrorContext?

    /// initialize KeyspacesStreams
    public init?(errorCode: String, context: AWSErrorContext) {
        guard let error = Code(rawValue: errorCode) else { return nil }
        self.error = error
        self.context = context
    }

    internal init(_ error: Code) {
        self.error = error
        self.context = nil
    }

    /// return error code string
    public var errorCode: String { self.error.rawValue }

    /// You don't have sufficient access permissions to perform this operation.  This exception occurs when your IAM user or role lacks the required permissions to access the Amazon Keyspaces resource or perform the requested action. Check your IAM policies and ensure they grant the necessary permissions.
    public static var accessDeniedException: Self { .init(.accessDeniedException) }
    /// The Amazon Keyspaces service encountered an unexpected error while processing the request.  This internal server error is not related to your request parameters. Retry your request after a brief delay. If the issue persists, contact Amazon Web Services Support with details of your request to help identify and resolve the problem.
    public static var internalServerException: Self { .init(.internalServerException) }
    /// The requested resource doesn't exist or could not be found.  This exception occurs when you attempt to access a keyspace, table, stream, or other Amazon Keyspaces resource that doesn't exist or that has been deleted. Verify that the resource identifier is correct and that the resource exists in your account.
    public static var resourceNotFoundException: Self { .init(.resourceNotFoundException) }
    /// The request rate is too high and exceeds the service's throughput limits.  This exception occurs when you send too many requests in a short period of time. Implement exponential backoff in your retry strategy to handle this exception. Reducing your request frequency or distributing requests more evenly can help avoid throughput exceptions.
    public static var throttlingException: Self { .init(.throttlingException) }
    /// The request validation failed because one or more input parameters failed validation.  This exception occurs when there are syntax errors in the request, field constraints are violated, or required parameters are missing. To help you fix the issue, the exception message provides details about which parameter failed and why.
    public static var validationException: Self { .init(.validationException) }
}

extension KeyspacesStreamsErrorType: AWSServiceErrorType {
    public static let errorCodeMap: [String: AWSErrorShape.Type] = [
        "ValidationException": KeyspacesStreams.ValidationException.self
    ]
}

extension KeyspacesStreamsErrorType: Equatable {
    public static func == (lhs: KeyspacesStreamsErrorType, rhs: KeyspacesStreamsErrorType) -> Bool {
        lhs.error == rhs.error
    }
}

extension KeyspacesStreamsErrorType: CustomStringConvertible {
    public var description: String {
        return "\(self.error.rawValue): \(self.message ?? "")"
    }
}
